#include "ae_epoll.h"
#include "common.h"

apiState* Epoll::EpollCreate(int size)
{
    apiState* state = tcalloc(apiState);
    state->efd_ = epoll_create(256);
    if(state->efd_ < 0)
        exit(-1);
    
    state->ets_ = tcallocArray(epoll_event, size);
    return state;
}

int Epoll::AddEpoll(eventLoop* el, int fd, int mask)
{
    if(!el || !el->state_)
        return 0;

    apiState* state = (apiState*)el->state_;
    struct epoll_event e;

    int op = el->ets_[fd].mask_ == AE_NONE ? EPOLL_CTL_ADD : EPOLL_CTL_MOD;

    int event = 0;

    //合并老的mask
    mask |= el->ets_[fd].mask_;
    if(mask & AE_READABLE)event |= EPOLLIN;
    if(mask & AE_WRITABLE)event |= EPOLLOUT;

    e.events = event;
    e.data.fd = fd;
    return epoll_ctl(state->efd_, op, fd, &e);
}

int Epoll::DelEpoll(eventLoop* el, int fd, int delmask)
{
    if(!el || !el->state_ || fd < 0 || fd >= el->setsize_)
        return -1;

    apiState* state = (apiState*)el->state_;

    int mask = el->ets_[fd].mask_ & (~delmask);

    struct epoll_event ee;
    ee.events = 0;
    if(mask & AE_READABLE) ee.events |= EPOLLIN;
    if(mask & AE_WRITABLE) ee.events |= EPOLLOUT;
    ee.data.fd = fd;
    if(mask != AE_NONE)
    {
        return epoll_ctl(state->efd_, EPOLL_CTL_MOD, fd, &ee);
    }
    return epoll_ctl(state->efd_, EPOLL_CTL_DEL, fd, &ee);
}

int Epoll::ModEpoll(eventLoop* el, int fd)
{
    if(!el || !el->state_)
    return 0;

    apiState* state = (apiState*)el->state_;
    epoll_event e;
    //e.events = event;
    e.data.fd = fd;
    return epoll_ctl(state->efd_, EPOLL_CTL_MOD, fd, &e);
}

int Epoll::WaitEpoll(eventLoop* el, int timeout)
{
    if(!el || !el->state_)
        return 0;

    apiState* state = (apiState*)el->state_;
    int num = epoll_wait(state->efd_, state->ets_, el->setsize_, timeout); 
    for(int i = 0; i < num; ++i)
    {
        struct epoll_event* et = &state->ets_[i];
        int mask = 0;
        if(et->events & EPOLLIN) mask |= AE_READABLE;
        if(et->events & EPOLLOUT) mask |= AE_WRITABLE;

        struct fireEvent* fe = &el->fire_ets_[i];
        fe->fd_ = et->data.fd;
        fe->mask_ = mask;
    }
    return num;
}